package com.maycurobj.service.rabbitmq;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.maycur.developer.sdk.maycur.ultimate.openapi.response.PostReceiveApplicationResponse;
import com.maycurobj.domain.maycurDTO.BpmItineraryDTO;
import com.maycurobj.domain.maycurDTO.MultipleParticipantsDTO;
import com.maycurobj.entity.bpm.JobNumberDTO;
import com.maycurobj.entity.bpm.SalePlanOPDCADTO;
import com.maycurobj.repository.bpm.JobNumberMapper;
import com.maycurobj.repository.bpm.SalePlanOPDCAMapper;
import com.maycurobj.service.impl.opdca.OPDCAServiceImpl;
import com.maycurobj.util.NormalUtil;
import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.util.*;

import static com.maycurobj.util.opdca.OpdcaUtil.resultMap;

/**
 * 每刻 OPDCA 队列处理
 */
@Component
@Slf4j
public class OPDCAHandlerService {

    @Autowired
    private OPDCAServiceImpl opdcaService;

    @Autowired
    private JobNumberMapper convertJobNumber;

    @Autowired
    private SalePlanOPDCAMapper salePlanOPDCAMapper;

    @Autowired
    private JobNumberMapper jobNumberMapper;

    //参数配置
    private String HOST_NAME = "172.17.100.71";
    private Integer HOST_PORT=5672;
    private String USER_NAME = "admin";
    private String PASSWORD = "Bio-San@17";
    //    private static final String QUEUE_NAME = "first_queues";
    private static final String DLX_EXCHANGE = "dlx_exchange";
    private static final String NORMAL_QUEUE = "normal_queue";
    private static final String MAY_CUR_VIRTUAL_HOST = "/maycur_business";


    /**
     * 每刻OPDCA记录消费者 (对应多次重复)
     */
    @Bean
    public void maycurContinueCunsumer() throws Exception {
        log.info("监听队列");
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(HOST_NAME);
        factory.setPort(HOST_PORT);
        factory.setUsername(USER_NAME);
        factory.setPassword(PASSWORD);
        factory.setVirtualHost(MAY_CUR_VIRTUAL_HOST);
        Connection rabbitMQConnection = factory.newConnection();
        Channel channel = rabbitMQConnection.createChannel();
        channel.basicQos(1);

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            log.info("打印Bpm发出的行程 Received message: " + message);

            try {
                //正常处理业务
                BpmItineraryDTO dto = JSONObject.parseObject(JSONObject.toJSONString(message), BpmItineraryDTO.class);
                List<String> cities = new ArrayList<>();
                cities.add(dto.getToCityId());
                convertDesCity(dto, cities);
                dto.setToCityIds(cities);
                List<MultipleParticipantsDTO> list = dto.getParticipants();
                if (!Objects.isNull(dto.getParticipants())) {
                    List<JobNumberDTO> job = new ArrayList<>();
                    for (MultipleParticipantsDTO list1 : list) {
                        job.add(convertJobNumber.getUserID(list1.getId()));
                    }
                    dto.setJobNumber(job);
                }

                //整理行程 推送
                PostReceiveApplicationResponse response = null;
                dto.setNewFormCode(dto.getFormCode());
                if (!Objects.isNull(dto.getJobNumber())) {
                    int i = 0;
                    for (JobNumberDTO _s : dto.getJobNumber()) {
                        if (!_s.equals(dto.getEmpNo())) {
                            dto.setEmpNo(_s.getEmployeeNo());
                            dto.setNewFormCode(dto.getFormCode() + "--" + i);
                            response = opdcaService.importReferenceToMayCur(dto);
                            i++;
                        }
                    }
                }else{
                    response = opdcaService.importReferenceToMayCur(dto);
                }
                //返回的可能不会直接更新到字段中 通过服务层的方法接口回写
                Map<String, Object> ret = resultMap(response.getCode(), JSONObject.toJSONString(response), response.getData());
                Map<String, Object> ret2 = new HashMap<>();
                ret2.put("id", dto.getObjId());
                ret2.put("responseMsg", JSONObject.toJSONString(response));
                opdcaService.updateBpmOPDCAEntity(JSONObject.toJSONString(ret2));
                log.info("打印返回值:---->>>>{}", JSONObject.toJSONString(ret));
//                throw new Exception("OPDCA消息处理失败");
            } catch (Exception e) {
                AMQP.BasicProperties properties = delivery.getProperties();
                Map<String, Object> headers = properties.getHeaders() != null ? properties.getHeaders() : new HashMap<>();

                int retryCount = (int) headers.getOrDefault("x-retry-count", 0);

                if (retryCount < 1) {
                    // 第一次失败，重新发布到retry_queue_30s
                    headers.put("x-retry-count", retryCount + 1);
                    headers.put("x-death-reason", "first_retry");

                    AMQP.BasicProperties newProperties = new AMQP.BasicProperties.Builder()
                            .headers(headers)
                            .build();

                    channel.basicPublish(DLX_EXCHANGE, "retry_5m", newProperties, delivery.getBody());
                    log.info("消息已重新发布到retry_queue_5m===>" + NormalUtil.getNowTime());
                } else if (retryCount < 2) {
                    // 第二次失败，重新发布到retry_queue_60s
                    headers.put("x-retry-count", retryCount + 1);
                    headers.put("x-death-reason", "second_retry");

                    AMQP.BasicProperties newProperties = new AMQP.BasicProperties.Builder()
                            .headers(headers)
                            .build();

                    channel.basicPublish(DLX_EXCHANGE, "retry_20m", newProperties, delivery.getBody());
                    log.info("消息已重新发布到retry_queue_20m===>>" + NormalUtil.getNowTime());
                } else if (retryCount < 3) {
                    //第三次失败,重新发布到retry_queue_60m
                    headers.put("x-retry-count", retryCount + 1);
                    headers.put("x-death-reason", "three_retry");

                    AMQP.BasicProperties newProperties = new AMQP.BasicProperties.Builder()
                            .headers(headers)
                            .build();

                    channel.basicPublish(DLX_EXCHANGE, "retry_60m", newProperties, delivery.getBody());
                    log.info("消息已重新发布到retry_queue_60m===>>" + NormalUtil.getNowTime());
                } else {
                    // 所有重试失败，发布到error_queue
                    channel.basicPublish(DLX_EXCHANGE, "error", null, delivery.getBody());
                    log.info("消息已发送到error_queue===>>" + NormalUtil.getNowTime());
                }

                // 确认消息已被处理
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
            }
        };

        channel.basicConsume(NORMAL_QUEUE, false, deliverCallback, consumerTag -> {
        });

    }

    private BpmItineraryDTO privateBpmToServiceDto(SalePlanOPDCADTO entity) {
        JSONArray _partArray = null;
        if (StringUtils.isNotBlank(entity.getParticipants())) {
            _partArray = JSONArray.parseArray(entity.getParticipants());
        }
        entity.setParticipants(null);
        BpmItineraryDTO retDto = JSONObject.toJavaObject(JSON.parseObject(JSONObject.toJSONString(entity)), BpmItineraryDTO.class);
        //整理下多人员的信息
        if (!Objects.isNull(_partArray)) {
            List<JobNumberDTO> _list = new ArrayList<>();
            //根据id获取 工号
            for (Object _obj : _partArray) {
                JSONObject __obj = (JSONObject) _obj;
                JobNumberDTO _empNo = jobNumberMapper.getUserID(__obj.getString("id"));
                _list.add(_empNo);
            }
            retDto.setJobNumber(_list);
        }
        return retDto;
    }

    /**
     * 新增 中转城市 到目的城市中
     *
     * @param dto
     * @param cities
     */
    private void convertDesCity(BpmItineraryDTO dto, List<String> cities) {
        try {
            if (!Objects.isNull(dto.getPassing_through_cities())) {
                String str = dto.getPassing_through_cities().get("id").toString();
                String[] array = str.split(";");
                for (String list1 : array) {
                    cities.add(salePlanOPDCAMapper.getToCityId(list1));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info("convertDesCity 方法有异常");
        }
    }
}
